package staticClasses;

import java.util.ArrayList;

import players.Agent;
import players.Ball;
import players.GoalKeeper;
import players.Player;

/**
 * Don't forget to declare your variables and methods as static
 */
public class Global {
	
	public static boolean play = true;
	public static boolean pause = false;
	
	/**
	 * tick is the refresh rate for the manager.
	 * 50 is the standard for a real time game
	 * There's 20 tick in a second.
	 * if you want the max speed (processor's speed), change this value to 0
	 * twice speed is 25, half speed is 100, 1/4 speed is 200 etc...
	 */
	public static int tick = 50;
	
	public static long clock = 0;
	
	/**
	 * When you use the slide for the speed in the interface,
	 * it uses those possibilities to change the speed of the simulation.
	 * 1000 is very slow and 0 is the max speed.
	 */
	public static int[] simulationSpeedPossibilities = {1000,500,200,100,50,25,15,10,5,0};
	
	/**
	 * Level of team 1
	 */
	public static int team1Level = 0;
	
	/**
	 * Level of team 2
	 */
	public static int team2Level = 0;
	
	/**
	 * Score
	 */
	public static int[] score = {0,0};
	
	/**
	 * List of players of each team
	 * 
	 * Local team is assumed to be the left side one
	 * Visitor team is on the right side so.
	 */
	public static ArrayList<Player> localTeam;
	public static ArrayList<Player> visitorTeam = new ArrayList<Player>();
	
	/**
	 * Base characteristics of the different Player types
	 * the order is:
	 * { dribble_level, speed, power, intercept_level, accuracy, stamina }
	 * value from 0 to 255
	 * 1/4 value is 63
	 * mid value is 127
	 * 3/4 value is 191
	 */
	public static short[] baseGoalStats			= {999, 63,  150, 150, 150, 63  };//goal isn't "dribblable"
	public static short[] baseFullbackStats		= {150, 100, 100, 150, 127, 127 };
	public static short[] baseForwardStats		= {127, 150, 150, 100, 127, 127 };
	public static short[] baseMidfielderStats	= {127, 127, 127, 127, 127, 150 };
	
	/**
	 * Level adjustment matching the team global level (EASY, MEDIUM or HARD)
	 */
	public static short EASYadjust = -40;
	public static short HARDadjust = 40;
	
	
	/*
	 * Ball
	 * Ball's owner
	 */
	public static Ball ball;
	private static Player ballOwner;
	
	public static synchronized Player getBallOwner(){
		return Global.ballOwner;
	}
	
	public static synchronized void setBallOwner(Player p){
		Global.ballOwner=p;
	}
	
	// Map values
	public static int[] MapSize = {901,451};
	public static Square[][] Map;
	
	//some interesting squares of the map.
	public static ArrayList<int[]> localTeam_goalLine = new ArrayList<int[]>();
	public static ArrayList<int[]> visitorTeam_goalLine = new ArrayList<int[]>();
	public static ArrayList<int[]> midLine = new ArrayList<int[]>();
	public static ArrayList<int[]> leftLine = new ArrayList<int[]>();
	public static ArrayList<int[]> rightLine = new ArrayList<int[]>();
	public static ArrayList<int[]> topLine = new ArrayList<int[]>();
	public static ArrayList<int[]> bottomLine = new ArrayList<int[]>();
	public static Square center;
	public static Square localTeam_6meter;
	public static Square visitorTeam_6meter;
	
	/**
	 * Bresenham algorithm to get the list of point of a line.
	 * @param xi initial x axis
	 * @param yi initial y axis
	 * @param xf final x axis
	 * @param yf final y axis
	 * @return The list of point to go from (xi,yi) to (xf,yf) forming a line
	 */
	public static ArrayList<int[]> bresenham(int xi, int yi, int xf, int yf){
		
		int dx, dy, i, xinc, yinc, cumul, x, y ;
		ArrayList<int[]> listPoint = new ArrayList<int[]>();
		int[] point;
	 
		x = xi ;
		y = yi ;
		dx = xf - xi ;
		dy = yf - yi ;
		xinc = ( dx > 0 ) ? 1 : -1 ;
		yinc = ( dy > 0 ) ? 1 : -1 ;
		dx = Math.abs(dx) ;
		dy = Math.abs(dy) ;
		point = new int[2];
		point[0] = x;
		point[1] = y;
		listPoint.add(point);
	 
		if ( dx > dy ){
			cumul = dx / 2 ;
			for (i=1 ; i <= dx ; i++ ){
				x += xinc ;
				cumul += dy ;
				if ( cumul >= dx ){
					cumul -= dx ;
					y += yinc ;
				}
				point = new int[2];
				point[0] = x;
				point[1] = y;
				listPoint.add(point);
			}
		}
		else{
			cumul = dy / 2 ;
			for (i=1 ; i <= dy ; i++ ){
				y += yinc ;
				cumul += dx ;
				if ( cumul >= dy ){
					cumul -= dy ;
					x += xinc ;
				}
				point = new int[2];
				point[0] = x;
				point[1] = y;
				listPoint.add(point);
			}
		}
		return listPoint;
	}
	
	/**
	 * This algorithm find the shortest distance to a line calculated by
	 * Bresenham algorithm.
	 * @param xi initial x axis
	 * @param yi initial y axis
	 * @param line the list of points contained by the line.
	 * @return The list of point contained by the shortest line
	 */
	public static ArrayList<int[]> shortestLine(int xi, int yi, ArrayList<int[]> line){
		
		ArrayList<int[]> result = new ArrayList<int[]>();
		int distance=0;
		
		for(int index=0; index<line.size(); index++){
			ArrayList<int[]> temp = Global.bresenham(xi, yi, line.get(index)[0], line.get(index)[1]);
			if(index == 0){
				distance = temp.size();
				result = temp;
			}
			else{
				if(temp.size()<distance){
					result = temp;
					distance = temp.size();
				}
			}
		}
		
		return result;
		
	}
	
	public static Player nearestTeamMate(Player me){
		ArrayList<Player> team=null;
		if(me.isInLocalTeam){
			team = localTeam;
		}else{
			team = visitorTeam;
		}
		
		Player result=null;
		int dist = Integer.MAX_VALUE;
		for(Player p:team){
			if(!p.equals(me)){
				int d = (int)Math.pow((me.getPosition()[0] - p.getPosition()[0]),2) + 
						(int)Math.pow((me.getPosition()[1] - p.getPosition()[1]),2);
				if(dist>d){
					dist = d;
					result = p;
				}
			}
		}
		
		return result;
	}
	
	public static Player nearestOpponent(Player me, Square s){
		ArrayList<Player> team=null;
		if(me.isInLocalTeam){
			team = visitorTeam;
		}else{
			team = localTeam;
		}
		
		Player result=null;
		int dist = Integer.MAX_VALUE;
		for(Player p:team){
			int d = (int)Math.pow((s.x - p.getPosition()[0]),2) + 
					(int)Math.pow((s.y - p.getPosition()[1]),2);
			if(dist>d){
				dist = d;
				result = p;
			}
		}
		
		return result;
	}
	
	public static Player nearestOpponent(Player me){
		ArrayList<Player> team=null;
		if(me.isInLocalTeam){
			team = visitorTeam;
		}else{
			team = localTeam;
		}
		
		Player result=null;
		int dist = Integer.MAX_VALUE;
		for(Player p:team){
			int d = (int)Math.pow((me.getPosition()[0] - p.getPosition()[0]),2) + 
					(int)Math.pow((me.getPosition()[1] - p.getPosition()[1]),2);
			if(dist>d){
				dist = d;
				result = p;
			}
		}
		
		return result;
	}
	
	public static int distance(Agent A, Agent B){
		int d = (int)Math.sqrt(Math.pow((A.getPosition()[0]-B.getPosition()[0]),2) +
				Math.pow(A.getPosition()[1]-B.getPosition()[1],2));
		return d;
	}
	
	public static int d(Agent A, int x, int y){
		int d = (int)Math.sqrt(Math.pow(A.getPosition()[0]-x,2) +
				Math.pow(A.getPosition()[1]-y,2));
		return d;
	}
	
	public static int d(int x, int y, Agent A){
		int d = (int)Math.sqrt(Math.pow(A.getPosition()[0]-x,2) +
				Math.pow(A.getPosition()[1]-y,2));
		return d;
	}
	
	/**
	 * This function is just a alias for distance(Player A, Player B)
	 * @see dist(Player A, Player B)
	 * @param A the player A
	 * @param B the player B
	 * @return the distance between A and B
	 */
	public static int d(Agent A, Agent B){
		return distance(A,B);
	}
	
	/**
	 * search in a list of coordinates if it contains or not a square.
	 * @param x the x axis of the square we search
	 * @param y the y axis of the square we search
	 * @param the list of squares in which we search
	 * @return true if found, else false
	 */
	public static boolean inArray(int x, int y, ArrayList<int[]> list){
		
		for(int i=0;i<list.size();i++){
			if(list.get(i)[0]==x && list.get(i)[1]==y){
				return true;
			}
		}
		
		return false;
	}
	
	public static boolean inArray(Square s, ArrayList<int[]> list){
		return Global.inArray(s.x, s.y, list);
	}
}
